#include "sftmr.h"

static sftmr_t *sftmr_list_head =NULL;
static sftmr_t *sftmr_list_tail =NULL;

// process all the timers in the list
void sftmr_process( void )
{
    sftmr_tk_t current_time = BeeGetTick();
    static sftmr_tk_t last_time;

    if (last_time != current_time) { // if the time is changed
        last_time = current_time;
        for (sftmr_t *prev_node = NULL, *node = sftmr_list_head; node != NULL;) {
            if ((node->reload != (sftmr_tk_t)(-1)) && ((sftmr_tk_t)(current_time - node->timeout) <= ((sftmr_tk_t)(-1)>>1))) {
                checkACCESS(node->handle_func);
                node->handle_func(node->arg); // call the callback function
                if (node->reload != 0) {
                    node->timeout = current_time + node->reload; // update the timeout
                } else {
                    node->reload = (sftmr_tk_t)(-1); // stop the timer
                }
            }
            if (prev_node == NULL) {
                if (node != sftmr_list_head) {
                    node = sftmr_list_head;
                } else {
                    prev_node = node;
                    node = node->next;
                }
            } else {
                prev_node = prev_node->next;
                node = prev_node->next;
            }
        }
    }
}

// create a new timer and add it to the list
// if new_timer is NULL, it will malloc a new timer
// if new_timer is not NULL, it will use the new_timer as the timer
// return the timer if successful, NULL if failed
sftmr_t* sftmr_create(sftmr_t *new_timer, void (*handler)(void *), void *arg)
{
    checkACCESS(handler);

    if (new_timer == NULL) { // check if the timer is NULL
        new_timer = (sftmr_t*)(BeeMalloc(sizeof(sftmr_t)));
        if (new_timer == NULL) { // check if the malloc is successful
            return NULL;
        }
        new_timer->malloc_type =1;
    }
    new_timer->next = NULL;
    new_timer->handle_func = handler;
    new_timer->arg = arg;
    new_timer->is_running = 0;
    new_timer->is_isr = 0;
    new_timer->reload = (sftmr_tk_t)(-1);
    new_timer->timeout = 0;

    for (sftmr_t *node = sftmr_list_head ; node != NULL; node = node->next) {
        if (node == new_timer) {
            return node;
        }
    }
    if(sftmr_list_tail == NULL) {
        sftmr_list_head = new_timer;
        sftmr_list_tail = new_timer;
    } else {
        sftmr_list_tail->next = new_timer;
        sftmr_list_tail = new_timer;
    }

    return new_timer;
}

// delete a timer from the list and free the memory
// return 0 if successful, -1 if failed
int sftmr_delete(sftmr_t *timer)
{
    checkACCESS(timer);
    for (sftmr_t *pre_node = NULL, *node = sftmr_list_head ; node != NULL; pre_node = node, node = node->next) {
        if (node == timer) {
            if (node == sftmr_list_head) {
                sftmr_list_head = node->next;
            } else {
                pre_node->next = node->next;
            }
            if(node->malloc_type == 1) {
                BeeFree(node);
            }
            return 0;
        }
    }
    return -1;
}

// start a timer with a timeout and an reload
void sftmr_start(sftmr_t* timer, sftmr_tk_t timeout, sftmr_tk_t reload)
{
    checkACCESS(timer);
    timer->reload = (reload == (sftmr_tk_t)(-1)) ? (reload - 1) : reload;
    timer->timeout = BeeGetTick() + timeout;
}

// stop a timer
void sftmr_stop(sftmr_t* timer)
{
    checkACCESS(timer);
    timer->reload = (sftmr_tk_t)(-1);
}




